﻿#region Header

// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;
using System.Threading;
using ScrumTable.Common.Logging;
using ScrumTable.Common.SysLibs;
using ScrumTable.Common.Threading;

#endregion

namespace ScrumTable.Common.FileSystem
{
    /// <summary>
    /// Downloads a file from a internet server and monitors the file process. 
    /// </summary>
    public class FileProcessor
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private static readonly MessageQueue<FileInfo> FileBackgroundSaver = new MessageQueue<FileInfo>();

        private readonly Uri _filePath;
        private readonly Action<bool> _fileEditCompleted;
        private readonly Action _fileDownloadCompleted;
        private readonly FileInfo _localFile;
        private readonly IDataSyncDispatcher _dispatcher;
        private Process _myProcess;
        private DateTime _changed;
        private Timer _timer;
        
        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------
        
        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new FileProcssor Instance
        /// </summary>
        /// <param name="credentials"></param>
        /// <param name="dispatcher"></param>
        /// <param name="filePath"></param>
        /// <param name="localfilePath"></param>
        /// <param name="fileDownloadCompleted">fires after the the file has downloaded</param>
        /// <param name="fileEditCompleted">fires after the user closed the program. True = file has changed</param>
        public FileProcessor(ICredentials credentials, IDataSyncDispatcher dispatcher, Uri filePath, string localfilePath, Action fileDownloadCompleted, Action<bool> fileEditCompleted)
        {
            if (!filePath.IsAbsoluteUri)
            {
                filePath = new Uri(DataFolderUtil.GetDataFile(filePath.ToString()), UriKind.Absolute);
            }
            _filePath = filePath;
            _localFile = new FileInfo(localfilePath);
            _fileDownloadCompleted = fileDownloadCompleted;
            _fileEditCompleted =  fileEditCompleted;
            _dispatcher = dispatcher;

            DownloadAndShowFile(credentials);
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------
        
        /// <summary>
        /// Gets a random upload filepath (relativ and absolute)
        /// </summary>
        /// <param name="filePathRel"></param>
        /// <param name="filePathAbs"></param>
        /// <param name="fileExtension"></param>
        public static void GetFilePathAbsAndRel(out string filePathRel, out string filePathAbs, string fileExtension)
        {
            filePathRel = Guid.NewGuid().ToString("D") + fileExtension;
            filePathAbs = Path.Combine(DataFolderUtil.GetTempUploadFileAbsolute(), filePathRel);
        }

        /// <summary>
        /// downloads the file and stores 
        /// </summary>
        /// <param name="credintial">webrequest to the image</param>
        /// <returns></returns>
        public void DownloadAndShowFile(ICredentials credintial)
        {
            using (WebClient client = new WebClient())
            {
                client.DownloadFileCompleted += OnClientDownloadFileCompleted;
                client.Credentials = credintial;
             
                client.DownloadFileAsync(_filePath, _localFile.FullName);
            }
        }


        private void SaveFileBackToServer(FileInfo fileInfo)
        {
            if (_timer != null){_timer.Dispose();}

            if (!fileInfo.IsFileLocked())
            {
                _dispatcher.BeginInvoke(
                    () => _fileEditCompleted((File.GetLastWriteTime(_localFile.FullName) != _changed)));
            }
            else
            {
                //file is locked -> enqueue again and wait for 2 second
                TimerCallback tc = (a) => FileBackgroundSaver.Enqueue(new MessageQueueCall<FileInfo>(SaveFileBackToServer), (FileInfo) a);
                _timer = new Timer(tc, fileInfo, TimeSpan.FromSeconds(2), TimeSpan.FromMilliseconds(-1));
            }
        }

        #endregion

        #region Events

        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------
        private void OnClientDownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            _dispatcher.BeginInvoke(_fileDownloadCompleted);
            try
            {
                using (_myProcess = new Process())
                {
                    _changed = File.GetLastWriteTime(_localFile.FullName);
                    _myProcess.StartInfo.FileName = _localFile.FullName;
                    _myProcess.EnableRaisingEvents = true;
                    _myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
                    _myProcess.Start();
                    FileBackgroundSaver.Enqueue(new MessageQueueCall<FileInfo>(SaveFileBackToServer), _localFile);
                }
            }
            catch(Exception exception)
            {
                Logger<FileProcessor>.Warn(exception.Message, exception);
            }
        }
        #endregion
    }
}